#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>

// 控制台颜色定义
#define COLOR_BLACK 0
#define COLOR_BLUE 1
#define COLOR_GREEN 2
#define COLOR_CYAN 3
#define COLOR_RED 4
#define COLOR_MAGENTA 5
#define COLOR_YELLOW 6
#define COLOR_WHITE 7
#define COLOR_GRAY 8
#define COLOR_BRIGHT_BLUE 9
#define COLOR_BRIGHT_GREEN 10
#define COLOR_BRIGHT_CYAN 11
#define COLOR_BRIGHT_RED 12
#define COLOR_BRIGHT_MAGENTA 13
#define COLOR_BRIGHT_YELLOW 14
#define COLOR_BRIGHT_WHITE 15

// 游戏区域大小
#define WIDTH 60
#define HEIGHT 20

// 蛇的最大长度
#define MAX_LENGTH 100

// 方向控制
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4

// 边界点最大数量
#define MAX_BOUNDARIES 200

// 游戏状态
int gameState = 0; // 0:欢迎界面, 1:游戏中, 2:游戏结束, 3:说明界面
int score = 0;
int highScore = 0;
int speed = 200; // 蛇的移动速度(ms)
int direction = RIGHT;
int addscore=10;

// 边界点结构
typedef struct 
{
    int x;
    int y;
} BoundaryPoint;

// 蛇的结构
struct Snake 
{
    int x[MAX_LENGTH];
    int y[MAX_LENGTH];
    int length;
} snake;

// 食物位置
int foodX, foodY;

// 边界点数组
BoundaryPoint boundaryPoints[MAX_BOUNDARIES];
int boundaryCount = 0;

// 设置控制台光标位置
void gotoxy(int x, int y) 
{
    COORD coord;
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

// 设置控制台颜色
void setColor(int color) 
{
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

// 检查位置是否是边界
int isBoundary(int x, int y) 
{
    for (int i = 0; i < boundaryCount; i++) 
    {
        if (boundaryPoints[i].x == x && boundaryPoints[i].y == y) 
        {
            return 1;
        }
    }
    return 0;
}

// 绘制欢迎界面的字符画
void printSnakeArt() {
    system("cls");
    setColor(COLOR_BRIGHT_GREEN);

    gotoxy(25, 3);
    printf("  _________         __    __  ");
    gotoxy(25, 4);
    printf(" /   _____/  ____  |  |  |  | ");
    gotoxy(25, 5);
    printf(" \\_____  \\ _/ __ \\ |  |  |  | ");
    gotoxy(25, 6);
    printf(" /        \\  ___/ |  `--'  | ");
    gotoxy(25, 7);
    printf("/_______  / \\___  |>____  /  ");
    gotoxy(25, 8);
    printf("        \\/      \\/      \\/   ");

    setColor(COLOR_BRIGHT_YELLOW);
    gotoxy(35, 12);
    printf("贪吃蛇游戏");

    setColor(COLOR_BRIGHT_WHITE);
    gotoxy(32, 15);
    printf("1. 开始游戏");
    gotoxy(32, 16);
    printf("2. 游戏说明");
    gotoxy(32, 17);
    printf("3. 最高分");
    gotoxy(32, 18);
    printf("4. 退出游戏");

    setColor(COLOR_BRIGHT_CYAN);
    gotoxy(30, 20);
    printf("请选择(1-4): ");
}

// 从文件读取最高分
void readHighScore() {
    FILE* file = fopen("save.txt", "r");
    if (file) {
        fscanf(file, "%d", &highScore);
        fclose(file);
    }
    else {
        highScore = 0;
    }
}

// 保存最高分到文件
void saveHighScore() 
{
    FILE* file = fopen("save.txt", "w");
    if (file) 
    {
        fprintf(file, "%d", highScore);
        fclose(file);
    }
}

// 初始化边界点
void initBoundaries() 
{
    boundaryCount = 0;

    // 上边界
    for (int i = 0; i < WIDTH; i += 2) 
    {
        boundaryPoints[boundaryCount].x = i;
        boundaryPoints[boundaryCount].y = 0;
        boundaryCount++;
    }

    // 下边界
    for (int i = 0; i < WIDTH; i += 2) 
    {
        boundaryPoints[boundaryCount].x = i;
        boundaryPoints[boundaryCount].y = HEIGHT - 1;
        boundaryCount++;
    }

    // 左边界
    for (int i = 1; i < HEIGHT - 1; i++) 
    {
        boundaryPoints[boundaryCount].x = 0;
        boundaryPoints[boundaryCount].y = i;
        boundaryCount++;
    }

    // 右边界
    for (int i = 1; i < HEIGHT - 1; i++) 
    {
        boundaryPoints[boundaryCount].x = WIDTH - 2;
        boundaryPoints[boundaryCount].y = i;
        boundaryCount++;
    }
}

// 绘制游戏地图
void createMap() 
{
    setColor(COLOR_BRIGHT_BLUE);
    for (int i = 0; i < boundaryCount; i++) 
    {
        gotoxy(boundaryPoints[i].x, boundaryPoints[i].y);
        printf("■");
    }
}

// 初始化蛇
void initSnake() 
{
    snake.length = 5;
    // 初始化蛇的位置（水平方向）
    for (int i = 0; i < snake.length; i++) 
    {
        snake.x[i] = 24 - i * 2;
        snake.y[i] = 5;
    }
    direction = RIGHT;
}

// 生成食物
void createFood() 
{
    int validPosition;
    do {
        validPosition = 1;
        // 随机生成食物位置（确保在边界内）
        foodX = (rand() % (WIDTH / 2 - 4) + 2) * 2;
        foodY = rand() % (HEIGHT - 4) + 2;

        // 检查食物是否与蛇身重叠
        for (int i = 0; i < snake.length; i++) 
        {
            if (foodX == snake.x[i] && foodY == snake.y[i]) 
            {
                validPosition = 0;
                break;
            }
        }

        // 检查食物是否在边界上
        if (isBoundary(foodX, foodY)) 
        {
            validPosition = 0;
        }
    } while (!validPosition);

    // 绘制食物
    setColor(COLOR_BRIGHT_RED);
    gotoxy(foodX, foodY);
    printf("★");
}

// 绘制蛇
void drawSnake() {
    // 绘制蛇头
    setColor(COLOR_BRIGHT_YELLOW);
    gotoxy(snake.x[0], snake.y[0]);
    printf("●");

    // 绘制蛇身
    setColor(COLOR_YELLOW);
    for (int i = 1; i < snake.length; i++) 
    {
        gotoxy(snake.x[i], snake.y[i]);
        printf("◎");
    }
}

// 移动蛇
void moveSnake() {
    // 保存蛇尾位置
    int tailX = snake.x[snake.length - 1];
    int tailY = snake.y[snake.length - 1];

    // 移动蛇身
    for (int i = snake.length - 1; i > 0; i--) 
    {
        snake.x[i] = snake.x[i - 1];
        snake.y[i] = snake.y[i - 1];
    }

    // 根据方向移动蛇头
    switch (direction) 
    {
    case UP:
        snake.y[0]--;
        break;
    case DOWN:
        snake.y[0]++;
        break;
    case LEFT:
        snake.x[0] -= 2;
        break;
    case RIGHT:
        snake.x[0] += 2;
        break;
    }

    // 清除蛇尾（如果不是边界）
    if (!isBoundary(tailX, tailY)) 
    {
        gotoxy(tailX, tailY);
        printf("  ");
    }

    // 绘制移动后的蛇
    drawSnake();
}

// 检查碰撞
int checkCollision() 
{
    // 检查是否撞墙
    if (isBoundary(snake.x[0], snake.y[0])) 
    {
        return 1;
    }

    // 检查是否撞到自己
    for (int i = 1; i < snake.length; i++) 
    {
        if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i]) 
        {
            return 1;
        }
    }

    // 检查是否吃到食物
    if (snake.x[0] == foodX && snake.y[0] == foodY) 
    {
        // 增加蛇的长度
        if (snake.length < MAX_LENGTH) 
        {
            snake.length++;
            snake.x[snake.length - 1] = snake.x[snake.length - 2];
            snake.y[snake.length - 1] = snake.y[snake.length - 2];
        }

        // 增加分数
        score += addscore;
        if(speed>50) speed -= 10;
    

        // 生成新食物
        createFood();

        // 显示分数
        setColor(COLOR_BRIGHT_WHITE);
        gotoxy(WIDTH + 5, 5);
        printf("当前得分: %d", score);
    }

    return 0;
}

// 显示游戏信息
void showGameInfo() 
{
    setColor(COLOR_BRIGHT_WHITE);
    gotoxy(WIDTH + 5, 3);
    printf("贪吃蛇游戏");

    gotoxy(WIDTH + 5, 5);
    printf("当前得分: %d", score);

    gotoxy(WIDTH + 5, 7);
    printf("最高分: %d", highScore);

    gotoxy(WIDTH + 5, 10);
    printf("控制方式:");
    gotoxy(WIDTH + 5, 11);
    printf("↑ ↓ ← → : 方向控制");
    gotoxy(WIDTH + 5, 12);
    printf("F1: 加速");
    gotoxy(WIDTH + 5, 13);
    printf("F2: 减速");
    gotoxy(WIDTH + 5, 14);
    printf("ESC: 退出游戏");
}

// 显示游戏结束界面
void showGameOver() 
{
    system("cls");
    setColor(COLOR_BRIGHT_RED);

    gotoxy(30, 5);
    printf("游戏结束!");

    setColor(COLOR_BRIGHT_WHITE);
    gotoxy(28, 7);
    printf("你的得分: %d", score);

    // 更新最高分
    if (score > highScore) 
    {
        gotoxy(25, 9);
        printf("创纪录啦!最高分被你刷新啦!");
        highScore = score;
        saveHighScore();
    }
    else 
    {
        gotoxy(28, 9);
        printf("最高分: %d", highScore);
        gotoxy(25, 10);
        printf("距离最高分还差: %d", highScore - score);
    }

    setColor(COLOR_BRIGHT_YELLOW);
    gotoxy(25, 12);
    printf("1. 重新开始");
    gotoxy(25, 13);
    printf("2. 退出游戏");

    setColor(COLOR_BRIGHT_CYAN);
    gotoxy(25, 15);
    printf("请选择(1-2): ");

    char choice;
    do {
        choice = getch();
    } while (choice != '1' && choice != '2');

    if (choice == '1') 
    {
        gameState = 1;
        score = 0;
        speed = 200;
        initSnake();
        createFood();
    }
    else 
    {
        gameState = 0;
    }
}

// 显示游戏说明
void showInstructions() 
{
    system("cls");
    setColor(COLOR_BRIGHT_CYAN);

    gotoxy(30, 2);
    printf("游戏说明");

    setColor(COLOR_BRIGHT_WHITE);
    gotoxy(5, 5);
    printf("1. 使用方向键(↑↓←→)控制蛇的移动方向");
    gotoxy(5, 7);
    printf("2. 吃到食物(★)可以增加蛇的长度和得分");
    gotoxy(5, 9);
    printf("3. 撞到墙壁或自己的身体游戏结束");
    gotoxy(5, 11);
    printf("4. 按F1可以加速，按F2可以减速");
    gotoxy(5, 13);
    printf("5. 按ESC可以随时退出游戏");

    setColor(COLOR_BRIGHT_YELLOW);
    gotoxy(30, 17);
    printf("按任意键返回...");
    getch();
    gameState = 0;
}

// 主游戏循环
void gameLoop() 
{
    system("cls");
    initBoundaries();  // 初始化边界点
    createMap();       // 绘制游戏地图
    initSnake();       // 初始化蛇
    createFood();      // 创建食物
    drawSnake();       // 绘制蛇
    showGameInfo();    // 显示游戏信息

    while (1) 
    {
        // 检查键盘输入
        if (kbhit()) 
        {
            int key = getch();
            if (key == 224) 
            { // 方向键
                key = getch();
                switch (key) 
                {
                case 72: // 上
                    if (direction != DOWN) direction = UP;
                    break;
                case 80: // 下
                    if (direction != UP) direction = DOWN;
                    break;
                case 75: // 左
                    if (direction != RIGHT) direction = LEFT;
                    break;
                case 77: // 右
                    if (direction != LEFT) direction = RIGHT;
                    break;
                }
            }
            else if (key == 0) 
            { // 功能键
                key = getch();
                switch (key) 
                {
                case 59: // F1
                    if (speed > 50) speed -= 10;
                    addscore += 2;
                    break;
                case 60: // F2
                    if (speed < 400) speed += 20;
                    addscore -= 2;
                    break;
                }
            }
            else if (key == 27) 
            { // ESC
                gameState = 2;
                break;
            }
        }

        // 移动蛇
        moveSnake();

        // 检查碰撞
        if (checkCollision()) 
        {
            gameState = 2;
            break;
        }

        // 控制游戏速度
        Sleep(speed);
    }
}

// 主函数
int main() {
    // 设置随机种子
    srand((unsigned)time(NULL));

    // 隐藏光标
    CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);

    // 设置控制台窗口大小
    system("mode con cols=100 lines=30");

    // 读取最高分
    readHighScore();

    char choice;

    while (1) 
    {
        switch (gameState) {
        case 0: // 欢迎界面
            printSnakeArt();
            choice = getch();
            if (choice == '1') 
            {
                gameState = 1;
            }
            else if (choice == '2') 
            {
                gameState = 3;
            }
            else if (choice == '3') 
            {
                // 显示最高分
                system("cls");
                setColor(COLOR_BRIGHT_YELLOW);
                gotoxy(35, 10);
                printf("最高分: %d", highScore);
                gotoxy(30, 12);
                printf("按任意键返回...");
                getch();
            }
            else if (choice == '4') 
            {
                exit(0);
            }
            break;

        case 1: // 游戏主界面
            gameLoop();
            break;

        case 2: // 游戏结束
            showGameOver();
            break;

        case 3: // 游戏说明
            showInstructions();
            break;
        }
    }

    return 0;
}